﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace TuringCup
{
    /// <summary>
    /// 描述游戏状态,主要用于Client绘制游戏现场
    /// </summary>
    [DataContract]
    public class GameState
    {
        /// <summary>
        /// 表示细胞
        /// </summary>
        [DataContract]
        public class Cell
        {
            /// <summary>
            /// 表示生命值,但是在显示的时候仅显示整数
            /// </summary>
            [DataMember]
            public double hp;
            /// <summary>
            /// 细胞等级 0-4
            /// </summary>
            [DataMember]
            public int level;
            /// <summary>
            /// 该细胞属于哪一个玩家
            /// </summary>
            [DataMember]
            public int side;
            /// <summary>
            /// x坐标
            /// </summary>
            [DataMember]
            public int x;

            /// <summary>
            /// y坐标
            /// </summary>
            [DataMember]
            public int y;

            /// <summary>
            /// 是否为英雄单位
            /// </summary>
            [DataMember]
            public bool ishero;

            /// <summary>
            /// 伤害记分板
            /// </summary>
            [DataMember]
            public Dictionary<int, double> injured = new Dictionary<int, double>();

            /// <summary>
            /// 中立细胞占领进度
            /// </summary>
            [DataMember]
            public double occupy_progress = 0;

            /// <summary>
            /// 中立细胞占领目标
            /// </summary>
            [DataMember]
            public double occupy_goal;

            /// <summary>
            /// 当前中立细胞占领方
            /// </summary>
            [DataMember]
            public int occupy_side = 0;

            /// <summary>
            /// Cell类的构造函数
            /// </summary>
            /// <param name="hp">生命值</param>
            /// <param name="side">阵营</param>
            /// <param name="x">x坐标</param>
            /// <param name="y">y坐标</param>
            /// <param name="ishero">是否英雄</param>
            public Cell(int hp, int side, int x, int y, bool ishero)
            {
                this.hp = hp;
                this.side = side;
                this.x = x;
                this.y = y;
                this.ishero = ishero;
            }
            /// <summary>
            /// 伤害某个细胞
            /// </summary>
            /// <param name="cell">攻击者细胞编号</param>
            /// <param name="cellside">攻击者阵营</param>
            /// <param name="harm">攻击伤害</param>
            public void Harm(int cell, int cellside, double harm)
            {
                if (side == 0)
                {
                    if (cellside == occupy_side)
                        occupy_progress += harm;
                    else
                    {
                        occupy_progress -= harm;
                        if (occupy_progress < 0)
                        {
                            occupy_side = cellside;
                            occupy_progress = -occupy_progress;
                        }
                    }
                    if (occupy_progress > occupy_goal)
                        side = cellside;
                }
                else
                {
                    //英雄不受伤害
                    if (ishero)
                        return;
                    if (!injured.ContainsKey(cell))
                        injured.Add(cell, 0.0);
                    injured[cell] += harm;
                    hp -= harm;
                }

            }
        }
        /// <summary>
        /// 表示一个触手实体
        /// </summary>
        [DataContract]
        public class Tentacle
        {
            /// <summary>
            /// 起始Cell下标
            /// </summary>
            [DataMember]
            public int begin;
            /// <summary>
            /// 终点Cell下标
            /// </summary>
            [DataMember]
            public int end;
            /// <summary>
            /// 触手连接在起始Cell的部分的长度
            /// </summary>
            [DataMember]
            public double len1;
            /// <summary>
            /// 是否已经断开
            /// </summary>
            [DataMember]
            public bool breaked;
            /// <summary>
            /// 触手连接在终点Cell部分的长度;
            /// </summary>
            [DataMember]
            public double len2;
            /// <summary>
            /// 每回合传递的能量
            /// </summary>
            [DataMember]
            public double energy;
            public Tentacle() { }
            public Tentacle(int begin, int end, double len1, bool breaked, double len2, double energy)
            {
                this.begin = begin;
                this.end = end;
                this.len1 = len1;
                this.breaked = breaked;
                this.len2 = len2;
                this.energy = energy;
            }
        }
        /// <summary>
        /// 在JSON中注明这是一个GameState包
        /// </summary>
        [DataMember]
        public const String package_type = "GameState";
        /// <summary>
        /// 表示地图上现存的所有Cell
        /// </summary>
        [DataMember]
        public List<Cell> cells = new List<Cell>();
        /// <summary>
        /// 表示地图上的所有Tentacle
        /// </summary>
        [DataMember]
        public List<Tentacle> tents = new List<Tentacle>();
        /// <summary>
        /// 游戏进行回合数
        /// </summary>
        [DataMember]
        public int tick_count = 0;

        /// <summary>
        /// 游戏配置
        /// </summary>
        [DataMember]
        public GameConfig gconfig = new GameConfig();

        /// <summary>
        /// 各方队伍名:
        /// </summary>
        [DataMember]
        public Dictionary<int,String> team_name = new Dictionary<int,String>();

        public GameState() { }
        /// <summary>
        /// 从JSON字符串中反序列化战场信息
        /// </summary>
        /// <param name="json">JSON字符串</param>
        /// <returns></returns>
        public static GameState Load(String json)
        {
            var mStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
            return Load(mStream);
        }
        /// <summary>
        /// 从JSON流中反序列化战场信息
        /// </summary>
        /// <param name="json">JSO流</param>
        /// <returns></returns>
        public static GameState Load(Stream json)
        {
            GameState gstate;
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(GameState));
            gstate = (GameState)ser.ReadObject(json);
            foreach (var cell in gstate.cells)
            {
                cell.injured = new Dictionary<int, double>();
            }
            return gstate;
        }
        /// <summary>
        /// 序列化GameState类   
        /// </summary>
        /// <returns>JSON字符串,表示当前对象的序列化结果</returns>
        public String Serialize()
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(GameState));
            MemoryStream stream = new MemoryStream();
            ser.WriteObject(stream, this);
            Byte[] dataBytes = new Byte[stream.Length];
            stream.Position = 0;
            stream.Read(dataBytes, 0, (int)stream.Length);
            String dataString = Encoding.UTF8.GetString(dataBytes);
            return dataString;
        }
        public void Add()
        {
            Random rnd = new Random();
            int x = rnd.Next(800);
            int y = rnd.Next(650);
            int hp = rnd.Next(15);
            cells.Add(new Cell(hp, 1, x, y, false));
        }
        /// <summary>
        /// a,b细胞之间的欧几里德距离
        /// </summary>
        /// <param name="a">a细胞</param>
        /// <param name="b">b细胞</param>
        /// <returns>a,b细胞之间的欧几里德距离</returns>
        public static double distance(Cell a, Cell b)
        {
            return Math.Sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
        }
        /// <summary>
        /// 进行一轮游戏
        /// </summary>
        /// <returns></returns>
        public GameState tick()
        {

            //记录攻击 
            List<Dictionary<int, bool>> attacked = new List<Dictionary<int, bool>>();
            for (int i = 0; i < cells.Count; i++)
            {
                attacked.Add(new Dictionary<int, bool>());
                for (int j = 0; j < cells.Count; j++)
                    attacked[i].Add(j, false);
            }
            double[] energy_in = new double[cells.Count];
            List<int>[] cell_tentcale = new List<int>[cells.Count];
            for (int i = 0; i < cells.Count; i++)
            {
                cell_tentcale[i] = new List<int>();
            }
            //构建列表,每个Cell发出那些Tentacle
            for (int i = 0; i < tents.Count; i++)
                cell_tentcale[tents[i].begin].Add(i);
            //枚举所有触手
            for (int tentindex = 0; tentindex < tents.Count; tentindex++)
            {
                Tentacle t = tents[tentindex];
                //寻找相对Tentacle
                Tentacle against = null;
                int againstindex = -1;
                double cell_dist = distance(cells[t.begin], cells[t.end]);//触须首尾距离
                for (int i = 0; i < cell_tentcale[t.end].Count; i++)
                {
                    if (tents[cell_tentcale[t.end][i]].end == t.begin)
                    {
                        againstindex = cell_tentcale[t.end][i];
                        against = tents[againstindex];
                    }

                }
                //判断接触
                if (!t.breaked && (t.len1 >= cell_dist - 1.0) || (against != null && t.len1 + against.len1 >= cell_dist - 1.0))//触须接触相对
                {
                    if (cells[t.begin].side == cells[t.end].side)
                        cells[t.end].hp += t.energy;
                    else
                    {
                        //cells[t.end].hp -= t.energy; //attack enemy
                        //cells[t.end].injured[t.begin] += t.energy;
                        cells[t.end].Harm(t.begin, cells[t.begin].side, t.energy);
                        attacked[t.end][t.begin] = true;
                    }

                    energy_in[t.end] += Math.Max(cells[t.end].hp - gconfig.c_maxhp, 0);
                    cells[t.end].hp = Math.Min(cells[t.end].hp, gconfig.c_maxhp);
                }
                //判断断开状态(收回状态)
                if (t.breaked)
                {
                    double d1 = Math.Min(gconfig.t_speed * 3.0, t.len1);//以延伸速度三倍收回
                    double d2 = Math.Min(gconfig.t_speed * 3.0, t.len2);//以延伸速度三倍攻击
                    t.len1 -= d1;
                    t.len2 -= d2;
                    cells[t.begin].hp += d1 * gconfig.t_density;
                    if (cells[t.begin].side == cells[t.end].side)
                        cells[t.end].hp += d2 * gconfig.t_density;
                    else
                    {
                        cells[t.end].Harm(t.begin, cells[t.begin].side, d2 * gconfig.t_density);
                        //cells[t.end].hp -= d2 * gconfig.t_density; //attack enemy
                        //cells[t.end].injured[t.begin] += d2 * gconfig.t_density;
                        attacked[t.end][t.begin] = true;
                    }
                }
                else
                {
                    double d = Math.Min(gconfig.t_speed, cell_dist - t.len1);//伸展距离
                    //if (against != null && t.len1 + against.len1 < cell_dist - 1.0 && )
                    if (against != null)
                    {
                        if (t.len1 + against.len1 > cell_dist - 1.0)//接触
                        {
                            d = Math.Max(-1.0 * gconfig.t_speed, Math.Min(d, cell_dist / 2 - t.len1));
                        }
                        else if (!t.breaked && !against.breaked && t.len1 + against.len1 + 2 * gconfig.t_speed > cell_dist) //处理两Tetnacle开始接触
                        {
                            if (tentindex < againstindex)
                            {
                                d = Math.Min(d, (cell_dist - t.len1 - against.len1) / 2);
                            }
                            else
                            {
                                d = Math.Min(d, (cell_dist - t.len1 - against.len1));
                            }                         
                        }

                    }
                    //此时d可能为负
                    if (cells[t.begin].hp - d * gconfig.t_density > 0.0)
                    {
                        t.len1 += d;
                        cells[t.begin].hp -= d * gconfig.t_density;
                    }
                    else
                        t.breaked = true;//自动收回
                }
            }
            for (int i = 0; i < cells.Count; i++)
            {
                Cell cell = cells[i];
                if (cell.side != 0)
                    cell.hp += gconfig.hp_recover[cell.level] / Math.Pow(2, cell_tentcale[i].Count);//计算生命值增加
                double energy_hp = Math.Min(gconfig.c_maxhp - cell.hp, energy_in[i]);
                cell.hp += energy_hp;
                energy_in[i] -= energy_hp;//计算可被利用于Tentacle的能量
                for (int j = 0; j < cell_tentcale[i].Count; j++)
                    tents[cell_tentcale[i][j]].energy = Math.Min(gconfig.max_output, gconfig.output[cell.level] + energy_in[i] / cell_tentcale[i].Count); //重新计算Tentcale 能量传输速度
                //清理攻击计分榜
                for (int j = 0; j < cells.Count; j++)
                    if (attacked[i][j] == false)
                        cell.injured.Remove(j);
                if (cell.hp < 0)
                {
                    if (cell.side != 0)
                    {
                        cell.hp = 10;
                        cell.side = cells[cell.injured.Aggregate((l, r) => l.Value > r.Value ? l : r).Key].side;
                        for (int j = 0; j < cell_tentcale[i].Count; j++)
                            tents[cell_tentcale[i][j]].breaked = true;//被转化后自动收回
                    }

                }
                for (int l = 0; l < 5; l++)
                {
                    if (cell.hp > gconfig.inchp[l] && cell.level < l)
                        cell.level = l;
                }
                for (int l = 0; l < 4; l++)
                {
                    if (cell.hp < gconfig.dechp[l] && cell.level > l)
                        cell.level = l;
                }
            }
            //从本行起不再有关于tents下标的逻辑
            //cell_tentcale 也将失效
            for (int i = tents.Count - 1; i >= 0; i--)
            {
                var t = tents[i];
                if (t.len1 <= 0 && t.len2 <= 0) //此时tents的下标变化不会再产生其他影响了
                    tents.Remove(t);
            }
            tick_count++;
            return null;
        }
        /// <summary>
        /// 执行AI的指令
        /// </summary>
        /// <param name="cmd">AI的指令,AI_Command类型</param>
        /// <param name="side">执行者的身份,side表示哪一方</param>
        public void AI_Order(AI_Commands cmd, int side)
        {
            int[] tentnum = new int[cells.Count];
            foreach (Tentacle t in tents)
                tentnum[t.begin]++;
            foreach (AI_Commands.NewTentacle nt in cmd.ntents)
                if (nt.begin < cells.Count && nt.end < cells.Count && side == cells[nt.begin].side)
                {
                    Tentacle against = null;
                    bool same = false;
                    foreach (GameState.Tentacle t in tents)
                    {
                        if (t.begin == nt.begin && t.end == nt.end)
                            same = true;
                        if (t.begin == nt.end && t.end == nt.begin)
                            against = t;
                    }
                    if (same || (against != null && against.breaked && against.len2 > 0))//不合法
                        continue;
                    //不能超过最大触须数量
                    if (tentnum[nt.begin] < gconfig.max_tent_num[cells[nt.begin].level])
                    {
                        tents.Add(new Tentacle(nt.begin, nt.end, 0.0, false, 0.0, 0));
                        cmd.btents.Add(new AI_Commands.BreakTentacle(nt.end, nt.begin, 1e10));
                        tentnum[nt.begin]++;
                    }
                }

            foreach (AI_Commands.BreakTentacle bt in cmd.btents)
                if (bt.begin < cells.Count && bt.end < cells.Count && side == cells[bt.begin].side)
                {
                    Tentacle t = null;
                    Tentacle against = null;
                    foreach (Tentacle tent in tents)
                    {
                        if (tent.begin == bt.begin && tent.end == bt.end)
                            t = tent;
                        if (tent.begin == bt.end && tent.end == bt.begin)
                            against = tent;
                    }
                    if (!(t == null || t.breaked))
                    {
                        if (!(against != null || t.breaked || t.len1 < distance(cells[bt.begin], cells[bt.end]) - 1.0 || bt.point > t.len1 || bt.point < 0 ))
                        {
                            t.len2 = t.len1 - bt.point;
                            t.len1 = bt.point;
                        }
                        t.breaked = true;
                    }
                }
        }
    }
}

